from types import MethodType
from enum import Enum, unique
class Teacher(object):
    pass

s = Teacher()
s.name = 'Michael'                  # 动态为实例绑定属性
print(s.name)

def set_age(self, age):             # 定义函数作为实例化方法
    self.age = age

s.set_age = MethodType(set_age, s)  # 为实例绑定方法（注意对其它实例不起作用）
s.set_age(25)
print(s.age)

Teacher.set_age = set_age            # 为class绑定方法


# 使用__slots__限制实例绑定的属性
class Person(object):
    __slots__ = ('name', 'age')       # 尝试为Person绑定非法属性将抛出AttributeError异常（仅对当前类有效）

# 使用@property
class Student(object):

    def __init__(self, score):
        self._score = score

    @property                        # 将getter方法变成属性，仅需加上@property即可
    def score(self):                 # 只定义getter方法，不定义setter方法就是一个只读属性
        return self._score

    @score.setter                    # @property本身又创建了另一个装饰器@score.setter，负责把一个setter方法变成属性赋值
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value >100:
            raise ValueError('score must between 1~100!')
        self._score = value

class Screen(object):
    def __init__(self, width = 0, height = 0):
        self._width = width
        self._height = height
        self._resolution = width * height

    @property
    def width(self):
        return self._width

    @width.setter
    def width(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        self._width = value

    @property
    def height(self):
        return self._height

    @height.setter
    def height(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        self._height = value

    @property
    def resolution(self):
        return self._width * self._height

# Screen类测试：
s = Screen()
s.width = 1024
s.height = 768
print('resolution =', s.resolution)
if s.resolution == 786432:
    print('测试通过!')
else:
    print('测试失败!')

# 多重继承（略）

# 定制类
class MyStudent(object):
    def __init__(self, name):
        self._name = name

    def __str__(self):                                        # 重定义字符串返回类型
        return 'MyStudent Object (name: %s)' % self._name

    __repr__ = __str__                                        # repr返回程序开发者看到的字符串

print(MyStudent('Michael'))


class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1       # 初始化计数器

    def __iter__(self):             # 实例本身就是迭代对象
        return self

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > 100:
            raise StopIteration()
        return self.a

    def __getitem__(self, n):
        if isinstance(n, int):      # 下表访问
            a, b = 1, 1
            for x in range(n):
                a, b = b, a + b
            return a
        elif isinstance(n, slice):  # 切片访问
            start, stop = n.start, n.stop
            if start is None:
                start = 0
            a, b = 1, 1
            L = []
            for x in range(stop):
                if x >= start:
                    L.append(a)
                a, b = b, a + b
            return L

for n in Fib():                          # 迭代器作用于定制类
    print(n)

print(Fib()[5])
print(Fib()[: 10])

class MyPerson(object):

    def __init__(self):
        self.name = 'Michael'

    def __getattr__(self, attr):         # 调用不存在的属性
        if attr == 'height':
            return 180
        if attr == 'weight':
            return lambda: 60
        return None

    def __call__(self, *args, **kwargs): # 定义类的实例调用
       print('My name is %s' % self.name)

person = MyPerson()
print(person())                          # 此处会多输出一个None，原因不明(需要排查)
print(callable(MyPerson()))
print(person.name)
print(person.height)
print(person.weight)
print(person.age)

# 枚举类
@unique
class Weekday(Enum):
    Sun = 0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6

for name, member in Weekday.__members__.items():
    print(name, '=>', member, ',', member.value)

def func(self, name = 'world'):
    print('Hello, %s' % name)

# 使用元类 (运行时创建类)
Hello = type('Hello', (object,), dict(hello = func))    # 创建Hello类型: class名称、继承的父类、方法绑定
h = Hello()
h.hello()
print(type(Hello))
print(type(h))

#
# =============================== 高能预警！！！ ===============================
#
# metaclass 元类(类的模板) ==> 允许创建和修改类
class ListMetaclass(type):                              # metaclass的类名总是以Metaclass结尾
    def __new__(cls, name, bases, attrs):               # 参数依次为：当前准备创建的类的对象，类的名字，类继承父类的集合，类的方法集合
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)

class MyList(list, metaclass = ListMetaclass):          # 关键词metaclass使创建MyList时必须
    pass

L = MyList()                                            # 动态修改类的方法
L.add(1)
print(L)

# ORM(Object Relational Mapping)框架
class Field(object):
    def __init__(self, name, column_type):
        self.name = name
        self.column_type = column_type

    def __str__(self):
        return '<%s:%s>' % (self.__class__.__name__, self.name)

class StringField(Field):
    def __init__(self):
        super(StringField, self).__init__(name, 'varchar(100)') # Python3调用super时可用super()替换super(class, self)

class IntegerField(Field):
    def __init__(self, name):
        super(IntegerField, self).__init__(name, 'bigint')

class ModelMetaClass(type):
    def __new__(cls, name,bases,attrs):
        if name == 'Model':
            return type.__new__(cls, name,bases,attrs)        # 排除掉对Model类的修改
        print('Found model: %s' % name)
        mapping = dict()
        for k, v in attrs.items():
            if isinstance(v, Field):
                print('Found mapping: %s => %s' % (k, v))
                mapping[k] = v

        for k in mapping.keys():
            attrs.pop(k)

        attrs['__mappings__'] = mapping    # 保存属性和列的映射关系
        attrs['__table__'] = name          # 表名和类名一致
        return type.__new__(cls, name,bases,attrs)

class Model(dict, metaclass = ModelMetaClass):
    def __init__(self, **kw):
        super(Model, self).__init__(**kw)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError('Model boject has no attribute %s' % key)

    def __setattr__(self, key, value):
        self[key] = value

    def save(self):
        fields = []
        params = []
        args = []
        for k, v in self.__mapping__.item():
            fields.append(v.name)
            params.append('?')
            args.append(getattr(self, k, None))
        sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
        print('SQL: %s' % sql)
        print('ARGS: %s' % str(args))

class User(Model):

    id = IntegerField('id')                                                          # 定义类的属性到列的映射
    name = StringField('username')
    email = StringField('email')
    password = StringField('password')


u = User(id = 12345, name = 'Michael', email = 'test@orm.org', password = 'my-pwd')  # 创建实例：
u.save()                                                                             # 保存到数据库：


